package com.cyf.common.core.math;

import com.cyf.common.core.coll.CollUtil;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author chenyifan
 * @create 2024-08-02 10:38
 */
public class DataUtil {

    /**
     * 数据求和
     * @param list 数据列表
     * @param fun 数据映射函数
     * @param scale 保留小数位数
     * @param defaultVal 默认值
     */
    public static <T> BigDecimal sum(List<T> list, Function<T, Number> fun, int scale, Number defaultVal) {
        if (CollectionUtils.isEmpty(list)) {
            return NumberUtil.toBigDecimal(defaultVal);
        }
        List<BigDecimal> numbers = list.stream()
                .filter(ele -> fun.apply(ele) != null)
                .map(ele -> NumberUtil.toBigDecimal(fun.apply(ele)))
                .collect(Collectors.toList());
        return NumberUtil.add(numbers).setScale(scale, RoundingMode.HALF_UP);
    }

    /**
     * 数据求均值
     * @param list 数据列表
     * @param fun 数据映射函数
     * @param scale 保留小数位数
     * @param defaultVal 默认值
     */
    public static <T> BigDecimal avg(List<T> list, Function<T, Number> fun, int scale, Number defaultVal) {
        if (CollectionUtils.isEmpty(list)) {
            return NumberUtil.toBigDecimal(defaultVal);
        }
        List<BigDecimal> numbers = list.stream()
                .filter(ele -> fun.apply(ele) != null)
                .map(ele -> NumberUtil.toBigDecimal(fun.apply(ele)))
                .collect(Collectors.toList());
        if (CollectionUtils.isEmpty(numbers)) {
            return NumberUtil.toBigDecimal(defaultVal);
        }
        return NumberUtil.div(NumberUtil.add(numbers), numbers.size(), scale);
    }

    /**
     * 数据按日期分组求均值
     * @param list 数据列表
     * @param fun 数据映射函数
     * @param timeFun 时间映射函数
     * @param scale 保留小数位数
     * @param defaultVal 默认值
     */
    public static <T> BigDecimal avgByTime(List<T> list, Function<T, Number> fun, Function<T, ?> timeFun, int scale, Number defaultVal) {
        if (CollectionUtils.isEmpty(list)) {
            return NumberUtil.toBigDecimal(defaultVal);
        }
        long count = list.stream().map(timeFun).distinct().count();
        return NumberUtil.div(sum(list, fun, scale, BigDecimal.ZERO), count, scale);
    }

    /**
     * 根据时间列表，填充没有的时间到列表中
     * @param timeList 时间列表
     * @param dataList 数据列表
     * @param timeFun 从数据元素中提取时间的函数。
     * @param dataFun 根据提供的时间生成元素对象，用于补空
     * @return
     */
    public static <E, T extends Comparable<T>> List<E> fillMissingTimeInList(List<T> timeList, List<E> dataList, Function<E, T> timeFun, Function<T, E> dataFun) {
        if (CollectionUtils.isEmpty(timeList)) {
            return new ArrayList<>();
        }
        List<T> existTimeList = dataList.stream().map(timeFun).collect(Collectors.toList());
        List<T> diff = CollUtil.diff(timeList, existTimeList);
        for (T time : diff) {
            dataList.add(dataFun.apply(time));
        }
        dataList.sort(Comparator.comparing(timeFun));
        return dataList;
    }

    /**
     * 计算百分比
     * @param part 部分
     * @param total 总数
     * @param scale 保留小数位数
     */
    public static <T> BigDecimal rate(Number part, Number total, int scale) {
        if (part == null || total == null || NumberUtil.toBigDecimal(total).compareTo(BigDecimal.ZERO) == 0) {
            return null;
        }
        return NumberUtil.mul(NumberUtil.div(part, total, scale + 2), 100).setScale(scale, RoundingMode.HALF_UP);
    }

    /**
     * 计算变化率
     * @param v1 数值1
     * @param v2 数值2
     * @param scale 保留小数位数
     */
    public static <T> BigDecimal changeRate(Number v1, Number v2, int scale) {
        if (v1 == null || v2 == null || NumberUtil.toBigDecimal(v2).compareTo(BigDecimal.ZERO) == 0) {
            return null;
        }
        return rate(NumberUtil.sub(v1, v2), v2, scale);
    }
}